/**
 * ChoiceFormatter
 *
 * @author Chris Pratt
 *
 * 11/17/2009
 */
package com.anodyzed.onyx.text;

import java.text.ChoiceFormat;
import java.util.ArrayList;
import java.util.List;

public class ChoiceFormatter extends TextFormatter {
  private double[] choiceLimits;
  private TextFormat[] choiceFormats;

  /**
   * Constructor
   *  
   * @param parent The parent TextFormat 
   * @param key The Argument Index of Map Key for this node 
   * @param bean The Additional Bean Reference String 
   * @param format The Format String 
   */
  public ChoiceFormatter (TextFormat parent,CharSequence key,CharSequence bean,CharSequence format) {
    super(parent,key,bean);
    StringBuilder buffer = new StringBuilder();
    List<Double> newChoiceLimits = new ArrayList<>();
    List<TextFormat> newChoiceFormats = new ArrayList<>();
    int part = 0;
    char ch;
    double startValue = 0;
    double oldStartValue = Double.NaN;
    boolean inQuote = false;
    String temp;
    for(int i = 0;i < format.length();++i) {
      ch = format.charAt(i);
      if(ch == '\'') {
          // Check for "''" indicating a literal quote
        if(((i + 1) < format.length()) && (format.charAt(i + 1) == ch)) {
          buffer.append(ch);
          ++i;
        } else {
          inQuote = !inQuote;
        }
      } else if(inQuote) {
        buffer.append(ch);
      } else if((ch == '<') || (ch == '#') || (ch == '\u2264')) {
        temp = buffer.toString().trim();
        if(temp.length() == 0) {
          throw new IllegalArgumentException("Segment must begin with a start value");
        }
        try {
          switch(temp) {
            case "\u221E":
              startValue = Double.POSITIVE_INFINITY;
              break;
            case "-\u221E":
              startValue = Double.NEGATIVE_INFINITY;
              break;
            default:
              startValue = Double.valueOf(temp);
              if(ch == '<') {
                startValue = ChoiceFormat.nextDouble(startValue);
              }
              break;
          }
        } catch(Exception x) {
          throw new IllegalArgumentException("Unable to determine start value from " + temp,x);
        }
        if(startValue <= oldStartValue) {
          throw new IllegalArgumentException("Segments must be in ascending order");
        }
        buffer.setLength(0);
        part = 1;
      } else if(ch == '|') {
        newChoiceLimits.add(startValue);
        newChoiceFormats.add(parent.subformat(buffer.toString()));
        oldStartValue = startValue;
        buffer.setLength(0);
        part = 0;
      } else {
        buffer.append(ch);
      }
    }
      // clean up last one
    if(part == 1) {
      newChoiceLimits.add(startValue);
      newChoiceFormats.add(parent.subformat(buffer.toString()));
    }
    int i = 0;
    choiceLimits = new double[newChoiceLimits.size()];
    for(double d : newChoiceLimits) {
      choiceLimits[i++] = d;
    }
    choiceFormats = newChoiceFormats.toArray(new TextFormat[newChoiceFormats.size()]);
  } //ChoiceFormatter

  /**
   * Constructor
   *  
   * @param parent The parent TextFormat 
   * @param key The Argument Index of Map Key for this node 
   * @param bean The Additional Bean Reference String 
   */
  public ChoiceFormatter (TextFormat parent,CharSequence key,CharSequence bean) {
    super(parent,key,bean);
    throw new IllegalArgumentException("Choice Formatter requires a format string");
  } //ChoiceFormatter

  /**
   * Return a string representation of the choice
   *
   * @param args The Formatting Arguments
   * @return The Formatted String
   */
  @Override
  public String toString (Object... args) {
    Number n = -1.0;
    Object o = getValue(args);
    if(o != null) {
      if(o instanceof Number) {
        n = (Number)o;
      } else {
        try {
          n = Long.valueOf(o.toString());
        } catch(NumberFormatException x) {
          try {
            n = Double.valueOf(o.toString());
          } catch(NumberFormatException y) {
            return null;
          }
        }
      }
    }
    int i;
    double number = n.doubleValue();
    for(i = 0;i < choiceLimits.length;++i) {
      if(!(number >= choiceLimits[i])) { // same as number < choiceLimits, except catches NaN
        break;
      }
    }
    if(--i < 0) {
      i = 0;
    }
      // return either a formatted number, or a string
    return choiceFormats[i].format(args);
  } //toString

} //*ChoiceFormatter
